# -*- coding: utf-8 -*- 
#! /usr/bin/python
import string
import socket
import re
import zlib
import sqlite3
from os import path

DATABASE_FILENAME = 'regex_data.sqlite'
SPAM, NOT_SPAM = True, False 

class SQLiteConnector(object):
    sim_r = []
    text_r = []
    sim_c = []
    text_c = []
    local_sim_r = []
    local_text_r = []
    local_sim_c = []
    local_text_c = []
    
    def __init__(self, custom_database = False):
        """ Initiate sqlite connector object
            If no database created yet (fist run, or removed), create it
        """
        if custom_database:
            global DATABASE_FILENAME
            DATABASE_FILENAME = custom_database
        # connect to sqlite
        if not path.isfile(DATABASE_FILENAME):
            print 'No database found, creating %s' % (DATABASE_FILENAME)
            self.create_database()
        
    def create_database(self):
        """ Create new database with all tables
            If table already exists, do nothing
        """
        conn = sqlite3.connect(DATABASE_FILENAME)
        c = conn.cursor()
        for table in ('sim_r', 'text_r', 'local_sim_r', 'local_text_r'):
            try:
                c.execute('''create table %s (data text UNIQUE ON CONFLICT IGNORE)''' % (table, ))
            except sqlite3.OperationalError, v:
                print v
        conn.commit()
        c.close()

    def connect(self):
        """ Attach to sqlite database
        """
        self.conn = sqlite3.connect(DATABASE_FILENAME)
        self.c = self.conn.cursor()

    def disconnect(self):
        """ Detach to sqlite database
        """
        self.c.close()

    def load(self):
        """ Load all regex from sqlite
        """
        self.c.execute('''select * from sim_r''')
        self.sim_r = [str(elem[0]) for elem in self.c.fetchall()]
        self.c.execute('''select * from text_r''')
        self.text_r = [str(elem[0]) for elem in self.c.fetchall()]
        self.c.execute('''select * from local_sim_r''')
        self.local_sim_r = [str(elem[0]) for elem in self.c.fetchall()]
        self.c.execute('''select * from local_text_r''')
        self.local_text_r = [str(elem[0]) for elem in self.c.fetchall()]
        self.rebuild()

    def save(self):
        """ Save all object filters into database
        """
        print 'sims', self.sim_r, 'text', self.text_r, 'local sim', self.local_sim_r, 'local text', self.local_text_r 
        [self.c.execute('''insert into sim_r(data) values (?)''', [elem]) for elem in self.sim_r]
        [self.c.execute('''insert into text_r(data) values (?)''', [elem]) for elem in self.text_r]
        [self.c.execute('''insert into local_sim_r(data) values (?)''', [elem]) for elem in self.local_sim_r]
        [self.c.execute('''insert into local_text_r(data) values (?)''', [elem]) for elem in self.local_text_r]
        self.conn.commit()

    def rebuild(self):
        """ Rebuild (recompile) re's - this is only for tests
        """
        self.save()
        self.sim_c = [re.compile(entry) for entry in self.sim_r] 
        self.text_c = [re.compile(entry) for entry in self.text_r]
        self.local_sim_c = [re.compile(entry) for entry in self.local_sim_r] 
        self.local_text_c = [re.compile(entry) for entry in self.local_text_r]

                
class SpamEngine(object):
    """ SpamEngine connects to local regex database
        In case of incoming SMS, puts it under decision whatever it is spam or not
    """
    addr = None
    text_port = None
    sim_port = None
    rd = None
    
    def __init__(self):
        """ Create SQLite database connector object
        """
        self.addr = '127.0.0.1'
        self.commit_sim_port = 2000
        self.commit_text_port = 2001
        self.update_sim_port = 2002
        self.update_text_port = 2003
        
        self.rd = SQLiteConnector()
        self.rd.connect()
        try:
            self.rd.load()
        except sqlite3.OperationalError:
            self.rd.create_database()

    def mark_as_spam(self, sms_ref_number):
        """ Marks specified SMS as a spam
            @sms_ref_number - Incoming SMS reference number
        """
        print "Marking as spam", sms_ref_number

    def move_to_spambox(self, sms_ref_number):
        """ Move spam sms to spambox
            @sms_ref_number - Incoming SMS reference number
        """
        print "Moving into spambox", sms_ref_number

    def incoming_sms(self, sms_ref_number, sim_number, text):
        """ Process every incoming SMS to check if it is a spam
            Decision is made over both sim number and body text
            @sms_ref_number - Incoming SMS reference number
            @sim_number - incoming SMS SIM number
            @text - incoming SMS text body
        """
        #sim_number = str(sim_number)
        sim_list = self.rd.sim_c
        sim_list.extend(self.rd.local_sim_c)
        for sim_re in self.sim_list:
            match_obj = sim_re.match(sim_number)
            if match_obj:
                print "SIM matched", match_obj, sim_number
                self.mark_as_spam(sms_ref_number)
                self.move_to_spambox(sms_ref_number)
                return SPAM

        text_list = self.rd.text_c
        text_list.extend(self.rd.local_text_c)
        for text_re in text_list:
            match_obj = text_re.match(text)
            if match_obj:
                print "TEXT matched", match_obj, text
                self.mark_as_spam(sms_ref_number)
                self.move_to_spambox(sms_ref_number)
                return SPAM
        
        return NOT_SPAM

    def commit(self):
        """ Connect to remote XML-RPC running service
            to commit new regex entries to shared database
        """
        self.rd.local_text_r = ['custom_text_ala','custom_text_ma','custom_text_kota']
        self.rd.local_sim_r = ['custom_sim_ala','custom_sim_ma','custom_sim_kota']
        
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#, socket.SO_REUSEADDR)
        s.connect((self.addr, self.commit_sim_port))
        #s.send('blablabla')
        sum_list = list(s.send('%s\x00' % (sim)) for sim in self.rd.local_sim_r)
        s.close()

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((self.addr, self.commit_text_port))
        sum_list.extend(list(s.send('%s\x00' % (text)) for text in self.rd.local_text_r))
        s.close()        
        
    def update(self):
        """ Connect to remote XML-RPC running service
            to download all new regex data from shared server
        """
        sim_list = []
        text_list = []
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#, socket.SO_REUSEADDR)
        s.connect((self.addr, self.update_sim_port))
        download_data = ''
        while True:
            part = s.recv(1024)
            if not part:
                break
            download_data += part
        sim_list = download_data.split('\x00')
        sim_list.pop()
        print 'received sim_list', sim_list
        
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((self.addr, self.update_text_port))
        download_data = ''
        while True:
            part = s.recv(1024)
            if not part:
                break
            download_data += part
        text_list = download_data.split('\x00')
        text_list.pop()
        print 'received text_list', text_list

    def exit(self):
        """ Disconnect from local SQLite database
        """
        self.rd.disconnect()


if __name__ == '__main__':
    print "Welcome to SMS middleware"
    myEngine = SpamEngine()
    #myEngine.commit()
    #myEngine.update()
    #myEngine.commit()
    #myEngine.update()
    myEngine.exit()


